1 /*-------------------------------------------------------------------------
2  * drawElements Quality Program OpenGL ES Utilities
3  * ------------------------------------------------
4  *
5  * Copyright 2014 The Android Open Source Project
6  *
7  * Licensed under the Apache License, Version 2.0 (the "License");
8  * you may not use this file except in compliance with the License.
9  * You may obtain a copy of the License at
10  *
11  *      http://www.apache.org/licenses/LICENSE-2.0
12  *
13  * Unless required by applicable law or agreed to in writing, software
14  * distributed under the License is distributed on an "AS IS" BASIS,
15  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16  * See the License for the specific language governing permissions and
17  * limitations under the License.
18  *
19  *//*!
20  * \file
21  * \brief Utility functions and structures for texture tests. This code
22  * is originated from the modules/glshared/glsTextureTestUtil.hpp and it
23  * is tightly coupled with the GLES and Vulkan texture tests!
24  *//*--------------------------------------------------------------------*/
25 
26 #include "gluTextureTestUtil.hpp"
27 
28 #include "tcuFloat.hpp"
29 #include "tcuImageCompare.hpp"
30 #include "tcuTestLog.hpp"
31 #include "tcuVectorUtil.hpp"
32 
33 #include "deMath.h"
34 #include "deStringUtil.hpp"
35 
36 #include <string>
37 
38 using std::string;
39 
40 namespace glu
41 {
42 
43 namespace TextureTestUtil
44 {
45 
46 enum
47 {
48 	MIN_SUBPIXEL_BITS	= 4
49 };
50 
getSamplerType(tcu::TextureFormat format)51 SamplerType getSamplerType (tcu::TextureFormat format)
52 {
53 	using tcu::TextureFormat;
54 
55 	switch (format.type)
56 	{
57 		case TextureFormat::SIGNED_INT8:
58 		case TextureFormat::SIGNED_INT16:
59 		case TextureFormat::SIGNED_INT32:
60 			return SAMPLERTYPE_INT;
61 
62 		case TextureFormat::UNSIGNED_INT8:
63 		case TextureFormat::UNSIGNED_INT32:
64 		case TextureFormat::UNSIGNED_INT_1010102_REV:
65 			return SAMPLERTYPE_UINT;
66 
67 		// Texture formats used in depth/stencil textures.
68 		case TextureFormat::UNSIGNED_INT16:
69 		case TextureFormat::UNSIGNED_INT_24_8:
70 			return (format.order == TextureFormat::D || format.order == TextureFormat::DS) ? SAMPLERTYPE_FLOAT : SAMPLERTYPE_UINT;
71 
72 		default:
73 			return SAMPLERTYPE_FLOAT;
74 	}
75 }
76 
getFetchSamplerType(tcu::TextureFormat format)77 SamplerType getFetchSamplerType (tcu::TextureFormat format)
78 {
79 	using tcu::TextureFormat;
80 
81 	switch (format.type)
82 	{
83 		case TextureFormat::SIGNED_INT8:
84 		case TextureFormat::SIGNED_INT16:
85 		case TextureFormat::SIGNED_INT32:
86 			return SAMPLERTYPE_FETCH_INT;
87 
88 		case TextureFormat::UNSIGNED_INT8:
89 		case TextureFormat::UNSIGNED_INT32:
90 		case TextureFormat::UNSIGNED_INT_1010102_REV:
91 			return SAMPLERTYPE_FETCH_UINT;
92 
93 		// Texture formats used in depth/stencil textures.
94 		case TextureFormat::UNSIGNED_INT16:
95 		case TextureFormat::UNSIGNED_INT_24_8:
96 			return (format.order == TextureFormat::D || format.order == TextureFormat::DS) ? SAMPLERTYPE_FETCH_FLOAT : SAMPLERTYPE_FETCH_UINT;
97 
98 		default:
99 			return SAMPLERTYPE_FETCH_FLOAT;
100 	}
101 }
102 
getSubView(const tcu::Texture1DView & view,int baseLevel,int maxLevel)103 static tcu::Texture1DView getSubView (const tcu::Texture1DView& view, int baseLevel, int maxLevel)
104 {
105 	const int	clampedBase	= de::clamp(baseLevel, 0, view.getNumLevels()-1);
106 	const int	clampedMax	= de::clamp(maxLevel, clampedBase, view.getNumLevels()-1);
107 	const int	numLevels	= clampedMax-clampedBase+1;
108 	return tcu::Texture1DView(numLevels, view.getLevels()+clampedBase);
109 }
110 
getSubView(const tcu::Texture2DView & view,int baseLevel,int maxLevel)111 static tcu::Texture2DView getSubView (const tcu::Texture2DView& view, int baseLevel, int maxLevel)
112 {
113 	const int	clampedBase	= de::clamp(baseLevel, 0, view.getNumLevels()-1);
114 	const int	clampedMax	= de::clamp(maxLevel, clampedBase, view.getNumLevels()-1);
115 	const int	numLevels	= clampedMax-clampedBase+1;
116 	return tcu::Texture2DView(numLevels, view.getLevels()+clampedBase, view.isES2());
117 }
118 
getSubView(const tcu::TextureCubeView & view,int baseLevel,int maxLevel)119 static tcu::TextureCubeView getSubView (const tcu::TextureCubeView& view, int baseLevel, int maxLevel)
120 {
121 	const int							clampedBase	= de::clamp(baseLevel, 0, view.getNumLevels()-1);
122 	const int							clampedMax	= de::clamp(maxLevel, clampedBase, view.getNumLevels()-1);
123 	const int							numLevels	= clampedMax-clampedBase+1;
124 	const tcu::ConstPixelBufferAccess*	levels[tcu::CUBEFACE_LAST];
125 
126 	for (int face = 0; face < tcu::CUBEFACE_LAST; face++)
127 		levels[face] = view.getFaceLevels((tcu::CubeFace)face) + clampedBase;
128 
129 	return tcu::TextureCubeView(numLevels, levels);
130 }
131 
getSubView(const tcu::Texture3DView & view,int baseLevel,int maxLevel)132 static tcu::Texture3DView getSubView (const tcu::Texture3DView& view, int baseLevel, int maxLevel)
133 {
134 	const int	clampedBase	= de::clamp(baseLevel, 0, view.getNumLevels()-1);
135 	const int	clampedMax	= de::clamp(maxLevel, clampedBase, view.getNumLevels()-1);
136 	const int	numLevels	= clampedMax-clampedBase+1;
137 	return tcu::Texture3DView(numLevels, view.getLevels()+clampedBase);
138 }
139 
getSubView(const tcu::TextureCubeArrayView & view,int baseLevel,int maxLevel)140 static tcu::TextureCubeArrayView getSubView (const tcu::TextureCubeArrayView& view, int baseLevel, int maxLevel)
141 {
142 	const int	clampedBase	= de::clamp(baseLevel, 0, view.getNumLevels()-1);
143 	const int	clampedMax	= de::clamp(maxLevel, clampedBase, view.getNumLevels()-1);
144 	const int	numLevels	= clampedMax-clampedBase+1;
145 	return tcu::TextureCubeArrayView(numLevels, view.getLevels()+clampedBase);
146 }
147 
linearInterpolate(float t,float minVal,float maxVal)148 inline float linearInterpolate (float t, float minVal, float maxVal)
149 {
150 	return minVal + (maxVal - minVal) * t;
151 }
152 
linearInterpolate(float t,const tcu::Vec4 & a,const tcu::Vec4 & b)153 inline tcu::Vec4 linearInterpolate (float t, const tcu::Vec4& a, const tcu::Vec4& b)
154 {
155 	return a + (b - a) * t;
156 }
157 
bilinearInterpolate(float x,float y,const tcu::Vec4 & quad)158 inline float bilinearInterpolate (float x, float y, const tcu::Vec4& quad)
159 {
160 	float w00 = (1.0f-x)*(1.0f-y);
161 	float w01 = (1.0f-x)*y;
162 	float w10 = x*(1.0f-y);
163 	float w11 = x*y;
164 	return quad.x()*w00 + quad.y()*w10 + quad.z()*w01 + quad.w()*w11;
165 }
166 
triangleInterpolate(float v0,float v1,float v2,float x,float y)167 float triangleInterpolate (float v0, float v1, float v2, float x, float y)
168 {
169 	return v0 + (v2-v0)*x + (v1-v0)*y;
170 }
171 
triangleInterpolate(const tcu::Vec3 & v,float x,float y)172 float triangleInterpolate (const tcu::Vec3& v, float x, float y)
173 {
174 	return triangleInterpolate(v.x(), v.y(), v.z(), x, y);
175 }
176 
177 // 1D lookup LOD computation.
178 
computeLodFromDerivates(LodMode mode,float dudx,float dudy)179 float computeLodFromDerivates (LodMode mode, float dudx, float dudy)
180 {
181 	float p = 0.0f;
182 	switch (mode)
183 	{
184 		// \note [mika] Min and max bounds equal to exact with 1D textures
185 		case LODMODE_EXACT:
186 		case LODMODE_MIN_BOUND:
187 		case LODMODE_MAX_BOUND:
188 			p = de::max(deFloatAbs(dudx), deFloatAbs(dudy));
189 			break;
190 
191 		default:
192 			DE_ASSERT(DE_FALSE);
193 	}
194 
195 	return deFloatLog2(p);
196 }
197 
computeNonProjectedTriLod(LodMode mode,const tcu::IVec2 & dstSize,deInt32 srcSize,const tcu::Vec3 & sq)198 float computeNonProjectedTriLod (LodMode mode, const tcu::IVec2& dstSize, deInt32 srcSize, const tcu::Vec3& sq)
199 {
200 	float dux	= (sq.z() - sq.x()) * (float)srcSize;
201 	float duy	= (sq.y() - sq.x()) * (float)srcSize;
202 	float dx	= (float)dstSize.x();
203 	float dy	= (float)dstSize.y();
204 
205 	return computeLodFromDerivates(mode, dux/dx, duy/dy);
206 }
207 
208 // 2D lookup LOD computation.
209 
computeLodFromDerivates(LodMode mode,float dudx,float dvdx,float dudy,float dvdy)210 float computeLodFromDerivates (LodMode mode, float dudx, float dvdx, float dudy, float dvdy)
211 {
212 	float p = 0.0f;
213 	switch (mode)
214 	{
215 		case LODMODE_EXACT:
216 			p = de::max(deFloatSqrt(dudx*dudx + dvdx*dvdx), deFloatSqrt(dudy*dudy + dvdy*dvdy));
217 			break;
218 
219 		case LODMODE_MIN_BOUND:
220 		case LODMODE_MAX_BOUND:
221 		{
222 			float mu = de::max(deFloatAbs(dudx), deFloatAbs(dudy));
223 			float mv = de::max(deFloatAbs(dvdx), deFloatAbs(dvdy));
224 
225 			p = mode == LODMODE_MIN_BOUND ? de::max(mu, mv) : mu + mv;
226 			break;
227 		}
228 
229 		default:
230 			DE_ASSERT(DE_FALSE);
231 	}
232 
233 	return deFloatLog2(p);
234 }
235 
computeNonProjectedTriLod(LodMode mode,const tcu::IVec2 & dstSize,const tcu::IVec2 & srcSize,const tcu::Vec3 & sq,const tcu::Vec3 & tq)236 float computeNonProjectedTriLod (LodMode mode, const tcu::IVec2& dstSize, const tcu::IVec2& srcSize, const tcu::Vec3& sq, const tcu::Vec3& tq)
237 {
238 	float dux	= (sq.z() - sq.x()) * (float)srcSize.x();
239 	float duy	= (sq.y() - sq.x()) * (float)srcSize.x();
240 	float dvx	= (tq.z() - tq.x()) * (float)srcSize.y();
241 	float dvy	= (tq.y() - tq.x()) * (float)srcSize.y();
242 	float dx	= (float)dstSize.x();
243 	float dy	= (float)dstSize.y();
244 
245 	return computeLodFromDerivates(mode, dux/dx, dvx/dx, duy/dy, dvy/dy);
246 }
247 
248 // 3D lookup LOD computation.
249 
computeLodFromDerivates(LodMode mode,float dudx,float dvdx,float dwdx,float dudy,float dvdy,float dwdy)250 float computeLodFromDerivates (LodMode mode, float dudx, float dvdx, float dwdx, float dudy, float dvdy, float dwdy)
251 {
252 	float p = 0.0f;
253 	switch (mode)
254 	{
255 		case LODMODE_EXACT:
256 			p = de::max(deFloatSqrt(dudx*dudx + dvdx*dvdx + dwdx*dwdx), deFloatSqrt(dudy*dudy + dvdy*dvdy + dwdy*dwdy));
257 			break;
258 
259 		case LODMODE_MIN_BOUND:
260 		case LODMODE_MAX_BOUND:
261 		{
262 			float mu = de::max(deFloatAbs(dudx), deFloatAbs(dudy));
263 			float mv = de::max(deFloatAbs(dvdx), deFloatAbs(dvdy));
264 			float mw = de::max(deFloatAbs(dwdx), deFloatAbs(dwdy));
265 
266 			p = mode == LODMODE_MIN_BOUND ? de::max(de::max(mu, mv), mw) : (mu + mv + mw);
267 			break;
268 		}
269 
270 		default:
271 			DE_ASSERT(DE_FALSE);
272 	}
273 
274 	return deFloatLog2(p);
275 }
276 
computeNonProjectedTriLod(LodMode mode,const tcu::IVec2 & dstSize,const tcu::IVec3 & srcSize,const tcu::Vec3 & sq,const tcu::Vec3 & tq,const tcu::Vec3 & rq)277 float computeNonProjectedTriLod (LodMode mode, const tcu::IVec2& dstSize, const tcu::IVec3& srcSize, const tcu::Vec3& sq, const tcu::Vec3& tq, const tcu::Vec3& rq)
278 {
279 	float dux	= (sq.z() - sq.x()) * (float)srcSize.x();
280 	float duy	= (sq.y() - sq.x()) * (float)srcSize.x();
281 	float dvx	= (tq.z() - tq.x()) * (float)srcSize.y();
282 	float dvy	= (tq.y() - tq.x()) * (float)srcSize.y();
283 	float dwx	= (rq.z() - rq.x()) * (float)srcSize.z();
284 	float dwy	= (rq.y() - rq.x()) * (float)srcSize.z();
285 	float dx	= (float)dstSize.x();
286 	float dy	= (float)dstSize.y();
287 
288 	return computeLodFromDerivates(mode, dux/dx, dvx/dx, dwx/dx, duy/dy, dvy/dy, dwy/dy);
289 }
290 
projectedTriInterpolate(const tcu::Vec3 & s,const tcu::Vec3 & w,float nx,float ny)291 static inline float projectedTriInterpolate (const tcu::Vec3& s, const tcu::Vec3& w, float nx, float ny)
292 {
293 	return (s[0]*(1.0f-nx-ny)/w[0] + s[1]*ny/w[1] + s[2]*nx/w[2]) / ((1.0f-nx-ny)/w[0] + ny/w[1] + nx/w[2]);
294 }
295 
triDerivateX(const tcu::Vec3 & s,const tcu::Vec3 & w,float wx,float width,float ny)296 static inline float triDerivateX (const tcu::Vec3& s, const tcu::Vec3& w, float wx, float width, float ny)
297 {
298 	float d = w[1]*w[2]*(width*(ny - 1.0f) + wx) - w[0]*(w[2]*width*ny + w[1]*wx);
299 	return (w[0]*w[1]*w[2]*width * (w[1]*(s[0] - s[2])*(ny - 1.0f) + ny*(w[2]*(s[1] - s[0]) + w[0]*(s[2] - s[1])))) / (d*d);
300 }
301 
triDerivateY(const tcu::Vec3 & s,const tcu::Vec3 & w,float wy,float height,float nx)302 static inline float triDerivateY (const tcu::Vec3& s, const tcu::Vec3& w, float wy, float height, float nx)
303 {
304 	float d = w[1]*w[2]*(height*(nx - 1.0f) + wy) - w[0]*(w[1]*height*nx + w[2]*wy);
305 	return (w[0]*w[1]*w[2]*height * (w[2]*(s[0] - s[1])*(nx - 1.0f) + nx*(w[0]*(s[1] - s[2]) + w[1]*(s[2] - s[0])))) / (d*d);
306 }
307 
308 // 1D lookup LOD.
computeProjectedTriLod(LodMode mode,const tcu::Vec3 & u,const tcu::Vec3 & projection,float wx,float wy,float width,float height)309 static float computeProjectedTriLod (LodMode mode, const tcu::Vec3& u, const tcu::Vec3& projection, float wx, float wy, float width, float height)
310 {
311 	// Exact derivatives.
312 	float dudx	= triDerivateX(u, projection, wx, width, wy/height);
313 	float dudy	= triDerivateY(u, projection, wy, height, wx/width);
314 
315 	return computeLodFromDerivates(mode, dudx, dudy);
316 }
317 
318 // 2D lookup LOD.
computeProjectedTriLod(LodMode mode,const tcu::Vec3 & u,const tcu::Vec3 & v,const tcu::Vec3 & projection,float wx,float wy,float width,float height)319 static float computeProjectedTriLod (LodMode mode, const tcu::Vec3& u, const tcu::Vec3& v, const tcu::Vec3& projection, float wx, float wy, float width, float height)
320 {
321 	// Exact derivatives.
322 	float dudx	= triDerivateX(u, projection, wx, width, wy/height);
323 	float dvdx	= triDerivateX(v, projection, wx, width, wy/height);
324 	float dudy	= triDerivateY(u, projection, wy, height, wx/width);
325 	float dvdy	= triDerivateY(v, projection, wy, height, wx/width);
326 
327 	return computeLodFromDerivates(mode, dudx, dvdx, dudy, dvdy);
328 }
329 
330 // 3D lookup LOD.
computeProjectedTriLod(LodMode mode,const tcu::Vec3 & u,const tcu::Vec3 & v,const tcu::Vec3 & w,const tcu::Vec3 & projection,float wx,float wy,float width,float height)331 static float computeProjectedTriLod (LodMode mode, const tcu::Vec3& u, const tcu::Vec3& v, const tcu::Vec3& w, const tcu::Vec3& projection, float wx, float wy, float width, float height)
332 {
333 	// Exact derivatives.
334 	float dudx	= triDerivateX(u, projection, wx, width, wy/height);
335 	float dvdx	= triDerivateX(v, projection, wx, width, wy/height);
336 	float dwdx	= triDerivateX(w, projection, wx, width, wy/height);
337 	float dudy	= triDerivateY(u, projection, wy, height, wx/width);
338 	float dvdy	= triDerivateY(v, projection, wy, height, wx/width);
339 	float dwdy	= triDerivateY(w, projection, wy, height, wx/width);
340 
341 	return computeLodFromDerivates(mode, dudx, dvdx, dwdx, dudy, dvdy, dwdy);
342 }
343 
execSample(const tcu::Texture1DView & src,const ReferenceParams & params,float s,float lod)344 static inline tcu::Vec4 execSample (const tcu::Texture1DView& src, const ReferenceParams& params, float s, float lod)
345 {
346 	if (params.samplerType == SAMPLERTYPE_SHADOW)
347 		return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, lod), 0.0, 0.0, 1.0f);
348 	else
349 		return src.sample(params.sampler, s, lod);
350 }
351 
execSample(const tcu::Texture2DView & src,const ReferenceParams & params,float s,float t,float lod)352 static inline tcu::Vec4 execSample (const tcu::Texture2DView& src, const ReferenceParams& params, float s, float t, float lod)
353 {
354 	if (params.samplerType == SAMPLERTYPE_SHADOW)
355 		return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, lod), 0.0, 0.0, 1.0f);
356 	else
357 		return src.sample(params.sampler, s, t, lod);
358 }
359 
execSample(const tcu::TextureCubeView & src,const ReferenceParams & params,float s,float t,float r,float lod)360 static inline tcu::Vec4 execSample (const tcu::TextureCubeView& src, const ReferenceParams& params, float s, float t, float r, float lod)
361 {
362 	if (params.samplerType == SAMPLERTYPE_SHADOW)
363 		return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, r, lod), 0.0, 0.0, 1.0f);
364 	else
365 		return src.sample(params.sampler, s, t, r, lod);
366 }
367 
execSample(const tcu::Texture2DArrayView & src,const ReferenceParams & params,float s,float t,float r,float lod)368 static inline tcu::Vec4 execSample (const tcu::Texture2DArrayView& src, const ReferenceParams& params, float s, float t, float r, float lod)
369 {
370 	if (params.samplerType == SAMPLERTYPE_SHADOW)
371 		return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, r, lod), 0.0, 0.0, 1.0f);
372 	else
373 		return src.sample(params.sampler, s, t, r, lod);
374 }
375 
execSample(const tcu::TextureCubeArrayView & src,const ReferenceParams & params,float s,float t,float r,float q,float lod)376 static inline tcu::Vec4 execSample (const tcu::TextureCubeArrayView& src, const ReferenceParams& params, float s, float t, float r, float q, float lod)
377 {
378 	if (params.samplerType == SAMPLERTYPE_SHADOW)
379 		return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, r, q, lod), 0.0, 0.0, 1.0f);
380 	else
381 		return src.sample(params.sampler, s, t, r, q, lod);
382 }
383 
execSample(const tcu::Texture1DArrayView & src,const ReferenceParams & params,float s,float t,float lod)384 static inline tcu::Vec4 execSample (const tcu::Texture1DArrayView& src, const ReferenceParams& params, float s, float t, float lod)
385 {
386 	if (params.samplerType == SAMPLERTYPE_SHADOW)
387 		return tcu::Vec4(src.sampleCompare(params.sampler, params.ref, s, t, lod), 0.0, 0.0, 1.0f);
388 	else
389 		return src.sample(params.sampler, s, t, lod);
390 }
391 
sampleTextureNonProjected(const tcu::SurfaceAccess & dst,const tcu::Texture1DView & rawSrc,const tcu::Vec4 & sq,const ReferenceParams & params)392 static void sampleTextureNonProjected (const tcu::SurfaceAccess& dst, const tcu::Texture1DView& rawSrc, const tcu::Vec4& sq, const ReferenceParams& params)
393 {
394 	// Separate combined DS formats
395 	std::vector<tcu::ConstPixelBufferAccess>	srcLevelStorage;
396 	const tcu::Texture1DView					src					= getEffectiveTextureView(rawSrc, srcLevelStorage, params.sampler);
397 
398 	float										lodBias				= (params.flags & ReferenceParams::USE_BIAS) ? params.bias : 0.0f;
399 
400 	tcu::IVec2									dstSize				= tcu::IVec2(dst.getWidth(), dst.getHeight());
401 	int											srcSize				= src.getWidth();
402 
403 	// Coordinates and lod per triangle.
404 	tcu::Vec3									triS[2]				= { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
405 	float										triLod[2]			= { de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[0]) + lodBias, params.minLod, params.maxLod),
406 																		de::clamp(computeNonProjectedTriLod(params.lodMode, dstSize, srcSize, triS[1]) + lodBias, params.minLod, params.maxLod) };
407 
408 	for (int y = 0; y < dst.getHeight(); y++)
409 	{
410 		for (int x = 0; x < dst.getWidth(); x++)
411 		{
412 			float	yf		= ((float)y + 0.5f) / (float)dst.getHeight();
413 			float	xf		= ((float)x + 0.5f) / (float)dst.getWidth();
414 
415 			int		triNdx	= xf + yf >= 1.0f ? 1 : 0; // Top left fill rule.
416 			float	triX	= triNdx ? 1.0f-xf : xf;
417 			float	triY	= triNdx ? 1.0f-yf : yf;
418 
419 			float	s		= triangleInterpolate(triS[triNdx].x(), triS[triNdx].y(), triS[triNdx].z(), triX, triY);
420 			float	lod		= triLod[triNdx];
421 
422 			dst.setPixel(execSample(src, params, s, lod) * params.colorScale + params.colorBias, x, y);
423 		}
424 	}
425 }
426 
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 	const float									posEps				= 1.0f / float(1<<MIN_SUBPIXEL_BITS);
1360 
1361 	int											numFailed			= 0;
1362 
1363 	const tcu::Vec2 lodOffsets[] =
1364 	{
1365 		tcu::Vec2(-1,  0),
1366 		tcu::Vec2(+1,  0),
1367 		tcu::Vec2( 0, -1),
1368 		tcu::Vec2( 0, +1),
1369 	};
1370 
1371 	tcu::clear(errorMask, tcu::RGBA::green().toVec());
1372 
1373 	for (int py = 0; py < result.getHeight(); py++)
1374 	{
1375 		// Ugly hack, validation can take way too long at the moment.
1376 		if (watchDog)
1377 			qpWatchDog_touch(watchDog);
1378 
1379 		for (int px = 0; px < result.getWidth(); px++)
1380 		{
1381 			const tcu::Vec4	resPix	= (result.getPixel(px, py)		- sampleParams.colorBias) / sampleParams.colorScale;
1382 			const tcu::Vec4	refPix	= (reference.getPixel(px, py)	- sampleParams.colorBias) / sampleParams.colorScale;
1383 
1384 			// Try comparison to ideal reference first, and if that fails use slower verificator.
1385 			if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
1386 			{
1387 				const float		wx		= (float)px + 0.5f;
1388 				const float		wy		= (float)py + 0.5f;
1389 				const float		nx		= wx / dstW;
1390 				const float		ny		= wy / dstH;
1391 
1392 				const bool		tri0	= (wx-posEps)/dstW + (wy-posEps)/dstH <= 1.0f;
1393 				const bool		tri1	= (wx+posEps)/dstW + (wy+posEps)/dstH >= 1.0f;
1394 
1395 				bool			isOk	= false;
1396 
1397 				DE_ASSERT(tri0 || tri1);
1398 
1399 				// Pixel can belong to either of the triangles if it lies close enough to the edge.
1400 				for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
1401 				{
1402 					const float		triWx	= triNdx ? dstW - wx : wx;
1403 					const float		triWy	= triNdx ? dstH - wy : wy;
1404 					const float		triNx	= triNdx ? 1.0f - nx : nx;
1405 					const float		triNy	= triNdx ? 1.0f - ny : ny;
1406 
1407 					const tcu::Vec2	coord		(projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
1408 												 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
1409 					const tcu::Vec2	coordDx		= tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
1410 															triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
1411 					const tcu::Vec2	coordDy		= tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
1412 															triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
1413 
1414 					tcu::Vec2		lodBounds	= tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
1415 
1416 					// Compute lod bounds across lodOffsets range.
1417 					for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
1418 					{
1419 						const float		wxo		= triWx + lodOffsets[lodOffsNdx].x();
1420 						const float		wyo		= triWy + lodOffsets[lodOffsNdx].y();
1421 						const float		nxo		= wxo/dstW;
1422 						const float		nyo		= wyo/dstH;
1423 
1424 						const tcu::Vec2	coordDxo	= tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
1425 																triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
1426 						const tcu::Vec2	coordDyo	= tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
1427 																triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
1428 						const tcu::Vec2	lodO		= tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
1429 
1430 						lodBounds.x() = de::min(lodBounds.x(), lodO.x());
1431 						lodBounds.y() = de::max(lodBounds.y(), lodO.y());
1432 					}
1433 
1434 					const tcu::Vec2	clampedLod	= tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
1435 					if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix))
1436 					{
1437 						isOk = true;
1438 						break;
1439 					}
1440 				}
1441 
1442 				if (!isOk)
1443 				{
1444 					errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
1445 					numFailed += 1;
1446 				}
1447 			}
1448 		}
1449 	}
1450 
1451 	return numFailed;
1452 }
1453 
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)1454 bool verifyTextureResult (tcu::TestContext&						testCtx,
1455 						  const tcu::ConstPixelBufferAccess&	result,
1456 						  const tcu::Texture1DView&				src,
1457 						  const float*							texCoord,
1458 						  const ReferenceParams&				sampleParams,
1459 						  const tcu::LookupPrecision&			lookupPrec,
1460 						  const tcu::LodPrecision&				lodPrec,
1461 						  const tcu::PixelFormat&				pixelFormat)
1462 {
1463 	tcu::TestLog&	log				= testCtx.getLog();
1464 	tcu::Surface	reference		(result.getWidth(), result.getHeight());
1465 	tcu::Surface	errorMask		(result.getWidth(), result.getHeight());
1466 	int				numFailedPixels;
1467 
1468 	DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
1469 
1470 	sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
1471 	numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
1472 
1473 	if (numFailedPixels > 0)
1474 		log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
1475 
1476 	log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
1477 		<< tcu::TestLog::Image("Rendered", "Rendered image", result);
1478 
1479 	if (numFailedPixels > 0)
1480 	{
1481 		log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
1482 			<< tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
1483 	}
1484 
1485 	log << tcu::TestLog::EndImageSet;
1486 
1487 	return numFailedPixels == 0;
1488 }
1489 
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)1490 bool verifyTextureResult (tcu::TestContext&						testCtx,
1491 						  const tcu::ConstPixelBufferAccess&	result,
1492 						  const tcu::Texture2DView&				src,
1493 						  const float*							texCoord,
1494 						  const ReferenceParams&				sampleParams,
1495 						  const tcu::LookupPrecision&			lookupPrec,
1496 						  const tcu::LodPrecision&				lodPrec,
1497 						  const tcu::PixelFormat&				pixelFormat)
1498 {
1499 	tcu::TestLog&	log				= testCtx.getLog();
1500 	tcu::Surface	reference		(result.getWidth(), result.getHeight());
1501 	tcu::Surface	errorMask		(result.getWidth(), result.getHeight());
1502 	int				numFailedPixels;
1503 
1504 	DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
1505 
1506 	sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
1507 	numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
1508 
1509 	if (numFailedPixels > 0)
1510 		log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
1511 
1512 	log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
1513 		<< tcu::TestLog::Image("Rendered", "Rendered image", result);
1514 
1515 	if (numFailedPixels > 0)
1516 	{
1517 		log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
1518 			<< tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
1519 	}
1520 
1521 	log << tcu::TestLog::EndImageSet;
1522 
1523 	return numFailedPixels == 0;
1524 }
1525 
1526 //! 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)1527 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess&	result,
1528 							  const tcu::ConstPixelBufferAccess&	reference,
1529 							  const tcu::PixelBufferAccess&			errorMask,
1530 							  const tcu::TextureCubeView&			baseView,
1531 							  const float*							texCoord,
1532 							  const ReferenceParams&				sampleParams,
1533 							  const tcu::LookupPrecision&			lookupPrec,
1534 							  const tcu::LodPrecision&				lodPrec,
1535 							  qpWatchDog*							watchDog)
1536 {
1537 	DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1538 	DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1539 
1540 	std::vector<tcu::ConstPixelBufferAccess>	srcLevelStorage;
1541 	const tcu::TextureCubeView					src					= getEffectiveTextureView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel), srcLevelStorage, sampleParams.sampler);
1542 
1543 	const tcu::Vec4								sq					= tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
1544 	const tcu::Vec4								tq					= tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
1545 	const tcu::Vec4								rq					= tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
1546 
1547 	const tcu::IVec2							dstSize				= tcu::IVec2(result.getWidth(), result.getHeight());
1548 	const float									dstW				= float(dstSize.x());
1549 	const float									dstH				= float(dstSize.y());
1550 	const int									srcSize				= src.getSize();
1551 
1552 	// Coordinates per triangle.
1553 	const tcu::Vec3								triS[2]				= { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
1554 	const tcu::Vec3								triT[2]				= { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
1555 	const tcu::Vec3								triR[2]				= { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
1556 	const tcu::Vec3								triW[2]				= { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
1557 
1558 	const tcu::Vec2								lodBias				((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
1559 
1560 	const float									posEps				= 1.0f / float(1<<MIN_SUBPIXEL_BITS);
1561 
1562 	int											numFailed			= 0;
1563 
1564 	const tcu::Vec2 lodOffsets[] =
1565 	{
1566 		tcu::Vec2(-1,  0),
1567 		tcu::Vec2(+1,  0),
1568 		tcu::Vec2( 0, -1),
1569 		tcu::Vec2( 0, +1),
1570 
1571 		// \note Not strictly allowed by spec, but implementations do this in practice.
1572 		tcu::Vec2(-1, -1),
1573 		tcu::Vec2(-1, +1),
1574 		tcu::Vec2(+1, -1),
1575 		tcu::Vec2(+1, +1),
1576 	};
1577 
1578 	tcu::clear(errorMask, tcu::RGBA::green().toVec());
1579 
1580 	for (int py = 0; py < result.getHeight(); py++)
1581 	{
1582 		// Ugly hack, validation can take way too long at the moment.
1583 		if (watchDog)
1584 			qpWatchDog_touch(watchDog);
1585 
1586 		for (int px = 0; px < result.getWidth(); px++)
1587 		{
1588 			const tcu::Vec4	resPix	= (result.getPixel(px, py)		- sampleParams.colorBias) / sampleParams.colorScale;
1589 			const tcu::Vec4	refPix	= (reference.getPixel(px, py)	- sampleParams.colorBias) / sampleParams.colorScale;
1590 
1591 			// Try comparison to ideal reference first, and if that fails use slower verificator.
1592 			if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
1593 			{
1594 				const float		wx		= (float)px + 0.5f;
1595 				const float		wy		= (float)py + 0.5f;
1596 				const float		nx		= wx / dstW;
1597 				const float		ny		= wy / dstH;
1598 
1599 				const bool		tri0	= (wx-posEps)/dstW + (wy-posEps)/dstH <= 1.0f;
1600 				const bool		tri1	= (wx+posEps)/dstW + (wy+posEps)/dstH >= 1.0f;
1601 
1602 				bool			isOk	= false;
1603 
1604 				DE_ASSERT(tri0 || tri1);
1605 
1606 				// Pixel can belong to either of the triangles if it lies close enough to the edge.
1607 				for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
1608 				{
1609 					const float		triWx	= triNdx ? dstW - wx : wx;
1610 					const float		triWy	= triNdx ? dstH - wy : wy;
1611 					const float		triNx	= triNdx ? 1.0f - nx : nx;
1612 					const float		triNy	= triNdx ? 1.0f - ny : ny;
1613 
1614 					const tcu::Vec3	coord		(projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
1615 												 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
1616 												 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
1617 					const tcu::Vec3	coordDx		(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
1618 												 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
1619 												 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
1620 					const tcu::Vec3	coordDy		(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
1621 												 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
1622 												 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
1623 
1624 					tcu::Vec2		lodBounds	= tcu::computeCubeLodBoundsFromDerivates(coord, coordDx, coordDy, srcSize, lodPrec);
1625 
1626 					// Compute lod bounds across lodOffsets range.
1627 					for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
1628 					{
1629 						const float		wxo		= triWx + lodOffsets[lodOffsNdx].x();
1630 						const float		wyo		= triWy + lodOffsets[lodOffsNdx].y();
1631 						const float		nxo		= wxo/dstW;
1632 						const float		nyo		= wyo/dstH;
1633 
1634 						const tcu::Vec3	coordO		(projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
1635 													 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
1636 													 projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
1637 						const tcu::Vec3	coordDxo	(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
1638 													 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
1639 													 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
1640 						const tcu::Vec3	coordDyo	(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
1641 													 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
1642 													 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
1643 						const tcu::Vec2	lodO		= tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
1644 
1645 						lodBounds.x() = de::min(lodBounds.x(), lodO.x());
1646 						lodBounds.y() = de::max(lodBounds.y(), lodO.y());
1647 					}
1648 
1649 					const tcu::Vec2	clampedLod	= tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
1650 
1651 					if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix))
1652 					{
1653 						isOk = true;
1654 						break;
1655 					}
1656 				}
1657 
1658 				if (!isOk)
1659 				{
1660 					errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
1661 					numFailed += 1;
1662 				}
1663 			}
1664 		}
1665 	}
1666 
1667 	return numFailed;
1668 }
1669 
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)1670 bool verifyTextureResult (tcu::TestContext&						testCtx,
1671 						  const tcu::ConstPixelBufferAccess&	result,
1672 						  const tcu::TextureCubeView&			src,
1673 						  const float*							texCoord,
1674 						  const ReferenceParams&				sampleParams,
1675 						  const tcu::LookupPrecision&			lookupPrec,
1676 						  const tcu::LodPrecision&				lodPrec,
1677 						  const tcu::PixelFormat&				pixelFormat)
1678 {
1679 	tcu::TestLog&	log				= testCtx.getLog();
1680 	tcu::Surface	reference		(result.getWidth(), result.getHeight());
1681 	tcu::Surface	errorMask		(result.getWidth(), result.getHeight());
1682 	int				numFailedPixels;
1683 
1684 	DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
1685 
1686 	sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
1687 	numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
1688 
1689 	if (numFailedPixels > 0)
1690 		log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
1691 
1692 	log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
1693 		<< tcu::TestLog::Image("Rendered", "Rendered image", result);
1694 
1695 	if (numFailedPixels > 0)
1696 	{
1697 		log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
1698 			<< tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
1699 	}
1700 
1701 	log << tcu::TestLog::EndImageSet;
1702 
1703 	return numFailedPixels == 0;
1704 }
1705 
1706 //! 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)1707 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess&	result,
1708 							  const tcu::ConstPixelBufferAccess&	reference,
1709 							  const tcu::PixelBufferAccess&			errorMask,
1710 							  const tcu::Texture3DView&				baseView,
1711 							  const float*							texCoord,
1712 							  const ReferenceParams&				sampleParams,
1713 							  const tcu::LookupPrecision&			lookupPrec,
1714 							  const tcu::LodPrecision&				lodPrec,
1715 							  qpWatchDog*							watchDog)
1716 {
1717 	DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1718 	DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1719 
1720 	std::vector<tcu::ConstPixelBufferAccess>	srcLevelStorage;
1721 	const tcu::Texture3DView					src					= getEffectiveTextureView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel), srcLevelStorage, sampleParams.sampler);
1722 
1723 	const tcu::Vec4								sq					= tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
1724 	const tcu::Vec4								tq					= tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
1725 	const tcu::Vec4								rq					= tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
1726 
1727 	const tcu::IVec2							dstSize				= tcu::IVec2(result.getWidth(), result.getHeight());
1728 	const float									dstW				= float(dstSize.x());
1729 	const float									dstH				= float(dstSize.y());
1730 	const tcu::IVec3							srcSize				= tcu::IVec3(src.getWidth(), src.getHeight(), src.getDepth());
1731 
1732 	// Coordinates and lod per triangle.
1733 	const tcu::Vec3								triS[2]				= { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
1734 	const tcu::Vec3								triT[2]				= { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
1735 	const tcu::Vec3								triR[2]				= { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
1736 	const tcu::Vec3								triW[2]				= { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
1737 
1738 	const tcu::Vec2								lodBias				((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
1739 
1740 	const float									posEps				= 1.0f / float(1<<MIN_SUBPIXEL_BITS);
1741 
1742 	int											numFailed			= 0;
1743 
1744 	const tcu::Vec2 lodOffsets[] =
1745 	{
1746 		tcu::Vec2(-1,  0),
1747 		tcu::Vec2(+1,  0),
1748 		tcu::Vec2( 0, -1),
1749 		tcu::Vec2( 0, +1),
1750 	};
1751 
1752 	tcu::clear(errorMask, tcu::RGBA::green().toVec());
1753 
1754 	for (int py = 0; py < result.getHeight(); py++)
1755 	{
1756 		// Ugly hack, validation can take way too long at the moment.
1757 		if (watchDog)
1758 			qpWatchDog_touch(watchDog);
1759 
1760 		for (int px = 0; px < result.getWidth(); px++)
1761 		{
1762 			const tcu::Vec4	resPix	= (result.getPixel(px, py)		- sampleParams.colorBias) / sampleParams.colorScale;
1763 			const tcu::Vec4	refPix	= (reference.getPixel(px, py)	- sampleParams.colorBias) / sampleParams.colorScale;
1764 
1765 			// Try comparison to ideal reference first, and if that fails use slower verificator.
1766 			if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
1767 			{
1768 				const float		wx		= (float)px + 0.5f;
1769 				const float		wy		= (float)py + 0.5f;
1770 				const float		nx		= wx / dstW;
1771 				const float		ny		= wy / dstH;
1772 
1773 				const bool		tri0	= (wx-posEps)/dstW + (wy-posEps)/dstH <= 1.0f;
1774 				const bool		tri1	= (wx+posEps)/dstW + (wy+posEps)/dstH >= 1.0f;
1775 
1776 				bool			isOk	= false;
1777 
1778 				DE_ASSERT(tri0 || tri1);
1779 
1780 				// Pixel can belong to either of the triangles if it lies close enough to the edge.
1781 				for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
1782 				{
1783 					const float		triWx	= triNdx ? dstW - wx : wx;
1784 					const float		triWy	= triNdx ? dstH - wy : wy;
1785 					const float		triNx	= triNdx ? 1.0f - nx : nx;
1786 					const float		triNy	= triNdx ? 1.0f - ny : ny;
1787 
1788 					const tcu::Vec3	coord		(projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
1789 												 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
1790 												 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
1791 					const tcu::Vec3	coordDx		= tcu::Vec3(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
1792 															triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
1793 															triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
1794 					const tcu::Vec3	coordDy		= tcu::Vec3(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
1795 															triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
1796 															triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
1797 
1798 					tcu::Vec2		lodBounds	= tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDx.z(), coordDy.x(), coordDy.y(), coordDy.z(), lodPrec);
1799 
1800 					// Compute lod bounds across lodOffsets range.
1801 					for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
1802 					{
1803 						const float		wxo		= triWx + lodOffsets[lodOffsNdx].x();
1804 						const float		wyo		= triWy + lodOffsets[lodOffsNdx].y();
1805 						const float		nxo		= wxo/dstW;
1806 						const float		nyo		= wyo/dstH;
1807 
1808 						const tcu::Vec3	coordDxo	= tcu::Vec3(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
1809 																triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
1810 																triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
1811 						const tcu::Vec3	coordDyo	= tcu::Vec3(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
1812 																triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
1813 																triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
1814 						const tcu::Vec2	lodO		= tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDxo.z(), coordDyo.x(), coordDyo.y(), coordDyo.z(), lodPrec);
1815 
1816 						lodBounds.x() = de::min(lodBounds.x(), lodO.x());
1817 						lodBounds.y() = de::max(lodBounds.y(), lodO.y());
1818 					}
1819 
1820 					const tcu::Vec2	clampedLod	= tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
1821 
1822 					if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix))
1823 					{
1824 						isOk = true;
1825 						break;
1826 					}
1827 				}
1828 
1829 				if (!isOk)
1830 				{
1831 					errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
1832 					numFailed += 1;
1833 				}
1834 			}
1835 		}
1836 	}
1837 
1838 	return numFailed;
1839 }
1840 
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)1841 bool verifyTextureResult (tcu::TestContext&						testCtx,
1842 						  const tcu::ConstPixelBufferAccess&	result,
1843 						  const tcu::Texture3DView&				src,
1844 						  const float*							texCoord,
1845 						  const ReferenceParams&				sampleParams,
1846 						  const tcu::LookupPrecision&			lookupPrec,
1847 						  const tcu::LodPrecision&				lodPrec,
1848 						  const tcu::PixelFormat&				pixelFormat)
1849 {
1850 	tcu::TestLog&	log				= testCtx.getLog();
1851 	tcu::Surface	reference		(result.getWidth(), result.getHeight());
1852 	tcu::Surface	errorMask		(result.getWidth(), result.getHeight());
1853 	int				numFailedPixels;
1854 
1855 	DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
1856 
1857 	sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
1858 	numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
1859 
1860 	if (numFailedPixels > 0)
1861 		log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
1862 
1863 	log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
1864 		<< tcu::TestLog::Image("Rendered", "Rendered image", result);
1865 
1866 	if (numFailedPixels > 0)
1867 	{
1868 		log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
1869 			<< tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
1870 	}
1871 
1872 	log << tcu::TestLog::EndImageSet;
1873 
1874 	return numFailedPixels == 0;
1875 }
1876 
1877 //! 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)1878 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess&	result,
1879 							  const tcu::ConstPixelBufferAccess&	reference,
1880 							  const tcu::PixelBufferAccess&			errorMask,
1881 							  const tcu::Texture1DArrayView&		baseView,
1882 							  const float*							texCoord,
1883 							  const ReferenceParams&				sampleParams,
1884 							  const tcu::LookupPrecision&			lookupPrec,
1885 							  const tcu::LodPrecision&				lodPrec,
1886 							  qpWatchDog*							watchDog)
1887 {
1888 	DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1889 	DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1890 
1891 	std::vector<tcu::ConstPixelBufferAccess>	srcLevelStorage;
1892 	const tcu::Texture1DArrayView				src					= getEffectiveTextureView(baseView, srcLevelStorage, sampleParams.sampler);
1893 
1894 	const tcu::Vec4								sq					= tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
1895 	const tcu::Vec4								tq					= tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
1896 
1897 	const tcu::IVec2							dstSize				= tcu::IVec2(result.getWidth(), result.getHeight());
1898 	const float									dstW				= float(dstSize.x());
1899 	const float									dstH				= float(dstSize.y());
1900 	const float									srcSize				= float(src.getWidth()); // For lod computation, thus #layers is ignored.
1901 
1902 	// Coordinates and lod per triangle.
1903 	const tcu::Vec3								triS[2]				= { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
1904 	const tcu::Vec3								triT[2]				= { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
1905 	const tcu::Vec3								triW[2]				= { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
1906 
1907 	const tcu::Vec2								lodBias				((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
1908 
1909 	int											numFailed			= 0;
1910 
1911 	const tcu::Vec2 lodOffsets[] =
1912 	{
1913 		tcu::Vec2(-1,  0),
1914 		tcu::Vec2(+1,  0),
1915 		tcu::Vec2( 0, -1),
1916 		tcu::Vec2( 0, +1),
1917 	};
1918 
1919 	tcu::clear(errorMask, tcu::RGBA::green().toVec());
1920 
1921 	for (int py = 0; py < result.getHeight(); py++)
1922 	{
1923 		// Ugly hack, validation can take way too long at the moment.
1924 		if (watchDog)
1925 			qpWatchDog_touch(watchDog);
1926 
1927 		for (int px = 0; px < result.getWidth(); px++)
1928 		{
1929 			const tcu::Vec4	resPix	= (result.getPixel(px, py)		- sampleParams.colorBias) / sampleParams.colorScale;
1930 			const tcu::Vec4	refPix	= (reference.getPixel(px, py)	- sampleParams.colorBias) / sampleParams.colorScale;
1931 
1932 			// Try comparison to ideal reference first, and if that fails use slower verificator.
1933 			if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
1934 			{
1935 				const float		wx		= (float)px + 0.5f;
1936 				const float		wy		= (float)py + 0.5f;
1937 				const float		nx		= wx / dstW;
1938 				const float		ny		= wy / dstH;
1939 
1940 				const int		triNdx	= nx + ny >= 1.0f ? 1 : 0;
1941 				const float		triWx	= triNdx ? dstW - wx : wx;
1942 				const float		triWy	= triNdx ? dstH - wy : wy;
1943 				const float		triNx	= triNdx ? 1.0f - nx : nx;
1944 				const float		triNy	= triNdx ? 1.0f - ny : ny;
1945 
1946 				const tcu::Vec2	coord	(projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
1947 										 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
1948 				const float	coordDx		= triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy) * srcSize;
1949 				const float	coordDy		= triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx) * srcSize;
1950 
1951 				tcu::Vec2		lodBounds	= tcu::computeLodBoundsFromDerivates(coordDx, coordDy, lodPrec);
1952 
1953 				// Compute lod bounds across lodOffsets range.
1954 				for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
1955 				{
1956 					const float		wxo		= triWx + lodOffsets[lodOffsNdx].x();
1957 					const float		wyo		= triWy + lodOffsets[lodOffsNdx].y();
1958 					const float		nxo		= wxo/dstW;
1959 					const float		nyo		= wyo/dstH;
1960 
1961 					const float	coordDxo		= triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo) * srcSize;
1962 					const float	coordDyo		= triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo) * srcSize;
1963 					const tcu::Vec2	lodO		= tcu::computeLodBoundsFromDerivates(coordDxo, coordDyo, lodPrec);
1964 
1965 					lodBounds.x() = de::min(lodBounds.x(), lodO.x());
1966 					lodBounds.y() = de::max(lodBounds.y(), lodO.y());
1967 				}
1968 
1969 				const tcu::Vec2	clampedLod	= tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
1970 				const bool		isOk		= tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
1971 
1972 				if (!isOk)
1973 				{
1974 					errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
1975 					numFailed += 1;
1976 				}
1977 			}
1978 		}
1979 	}
1980 
1981 	return numFailed;
1982 }
1983 
1984 //! 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)1985 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess&	result,
1986 							  const tcu::ConstPixelBufferAccess&	reference,
1987 							  const tcu::PixelBufferAccess&			errorMask,
1988 							  const tcu::Texture2DArrayView&		baseView,
1989 							  const float*							texCoord,
1990 							  const ReferenceParams&				sampleParams,
1991 							  const tcu::LookupPrecision&			lookupPrec,
1992 							  const tcu::LodPrecision&				lodPrec,
1993 							  qpWatchDog*							watchDog)
1994 {
1995 	DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
1996 	DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
1997 
1998 	std::vector<tcu::ConstPixelBufferAccess>	srcLevelStorage;
1999 	const tcu::Texture2DArrayView				src					= getEffectiveTextureView(baseView, srcLevelStorage, sampleParams.sampler);
2000 
2001 	const tcu::Vec4								sq					= tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
2002 	const tcu::Vec4								tq					= tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
2003 	const tcu::Vec4								rq					= tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
2004 
2005 	const tcu::IVec2							dstSize				= tcu::IVec2(result.getWidth(), result.getHeight());
2006 	const float									dstW				= float(dstSize.x());
2007 	const float									dstH				= float(dstSize.y());
2008 	const tcu::Vec2								srcSize				= tcu::IVec2(src.getWidth(), src.getHeight()).asFloat(); // For lod computation, thus #layers is ignored.
2009 
2010 	// Coordinates and lod per triangle.
2011 	const tcu::Vec3								triS[2]				= { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2012 	const tcu::Vec3								triT[2]				= { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2013 	const tcu::Vec3								triR[2]				= { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2014 	const tcu::Vec3								triW[2]				= { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2015 
2016 	const tcu::Vec2								lodBias				((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2017 
2018 	int											numFailed			= 0;
2019 
2020 	const tcu::Vec2 lodOffsets[] =
2021 	{
2022 		tcu::Vec2(-1,  0),
2023 		tcu::Vec2(+1,  0),
2024 		tcu::Vec2( 0, -1),
2025 		tcu::Vec2( 0, +1),
2026 	};
2027 
2028 	tcu::clear(errorMask, tcu::RGBA::green().toVec());
2029 
2030 	for (int py = 0; py < result.getHeight(); py++)
2031 	{
2032 		// Ugly hack, validation can take way too long at the moment.
2033 		if (watchDog)
2034 			qpWatchDog_touch(watchDog);
2035 
2036 		for (int px = 0; px < result.getWidth(); px++)
2037 		{
2038 			const tcu::Vec4	resPix	= (result.getPixel(px, py)		- sampleParams.colorBias) / sampleParams.colorScale;
2039 			const tcu::Vec4	refPix	= (reference.getPixel(px, py)	- sampleParams.colorBias) / sampleParams.colorScale;
2040 
2041 			// Try comparison to ideal reference first, and if that fails use slower verificator.
2042 			if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2043 			{
2044 				const float		wx		= (float)px + 0.5f;
2045 				const float		wy		= (float)py + 0.5f;
2046 				const float		nx		= wx / dstW;
2047 				const float		ny		= wy / dstH;
2048 
2049 				const int		triNdx	= nx + ny >= 1.0f ? 1 : 0;
2050 				const float		triWx	= triNdx ? dstW - wx : wx;
2051 				const float		triWy	= triNdx ? dstH - wy : wy;
2052 				const float		triNx	= triNdx ? 1.0f - nx : nx;
2053 				const float		triNy	= triNdx ? 1.0f - ny : ny;
2054 
2055 				const tcu::Vec3	coord		(projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2056 											 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2057 											 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2058 				const tcu::Vec2	coordDx		= tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2059 														triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize;
2060 				const tcu::Vec2	coordDy		= tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2061 														triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize;
2062 
2063 				tcu::Vec2		lodBounds	= tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
2064 
2065 				// Compute lod bounds across lodOffsets range.
2066 				for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2067 				{
2068 					const float		wxo		= triWx + lodOffsets[lodOffsNdx].x();
2069 					const float		wyo		= triWy + lodOffsets[lodOffsNdx].y();
2070 					const float		nxo		= wxo/dstW;
2071 					const float		nyo		= wyo/dstH;
2072 
2073 					const tcu::Vec2	coordDxo	= tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2074 															triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize;
2075 					const tcu::Vec2	coordDyo	= tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2076 															triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize;
2077 					const tcu::Vec2	lodO		= tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
2078 
2079 					lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2080 					lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2081 				}
2082 
2083 				const tcu::Vec2	clampedLod	= tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2084 				const bool		isOk		= tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coord, clampedLod, resPix);
2085 
2086 				if (!isOk)
2087 				{
2088 					errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2089 					numFailed += 1;
2090 				}
2091 			}
2092 		}
2093 	}
2094 
2095 	return numFailed;
2096 }
2097 
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)2098 bool verifyTextureResult (tcu::TestContext&						testCtx,
2099 						  const tcu::ConstPixelBufferAccess&	result,
2100 						  const tcu::Texture1DArrayView&		src,
2101 						  const float*							texCoord,
2102 						  const ReferenceParams&				sampleParams,
2103 						  const tcu::LookupPrecision&			lookupPrec,
2104 						  const tcu::LodPrecision&				lodPrec,
2105 						  const tcu::PixelFormat&				pixelFormat)
2106 {
2107 	tcu::TestLog&	log				= testCtx.getLog();
2108 	tcu::Surface	reference		(result.getWidth(), result.getHeight());
2109 	tcu::Surface	errorMask		(result.getWidth(), result.getHeight());
2110 	int				numFailedPixels;
2111 
2112 	DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2113 
2114 	sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2115 	numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
2116 
2117 	if (numFailedPixels > 0)
2118 		log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
2119 
2120 	log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
2121 		<< tcu::TestLog::Image("Rendered", "Rendered image", result);
2122 
2123 	if (numFailedPixels > 0)
2124 	{
2125 		log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
2126 			<< tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
2127 	}
2128 
2129 	log << tcu::TestLog::EndImageSet;
2130 
2131 	return numFailedPixels == 0;
2132 }
2133 
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)2134 bool verifyTextureResult (tcu::TestContext&						testCtx,
2135 						  const tcu::ConstPixelBufferAccess&	result,
2136 						  const tcu::Texture2DArrayView&		src,
2137 						  const float*							texCoord,
2138 						  const ReferenceParams&				sampleParams,
2139 						  const tcu::LookupPrecision&			lookupPrec,
2140 						  const tcu::LodPrecision&				lodPrec,
2141 						  const tcu::PixelFormat&				pixelFormat)
2142 {
2143 	tcu::TestLog&	log				= testCtx.getLog();
2144 	tcu::Surface	reference		(result.getWidth(), result.getHeight());
2145 	tcu::Surface	errorMask		(result.getWidth(), result.getHeight());
2146 	int				numFailedPixels;
2147 
2148 	DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2149 
2150 	sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2151 	numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, lodPrec, testCtx.getWatchDog());
2152 
2153 	if (numFailedPixels > 0)
2154 		log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
2155 
2156 	log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
2157 		<< tcu::TestLog::Image("Rendered", "Rendered image", result);
2158 
2159 	if (numFailedPixels > 0)
2160 	{
2161 		log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
2162 			<< tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
2163 	}
2164 
2165 	log << tcu::TestLog::EndImageSet;
2166 
2167 	return numFailedPixels == 0;
2168 }
2169 
2170 //! 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)2171 int computeTextureLookupDiff (const tcu::ConstPixelBufferAccess&	result,
2172 							  const tcu::ConstPixelBufferAccess&	reference,
2173 							  const tcu::PixelBufferAccess&			errorMask,
2174 							  const tcu::TextureCubeArrayView&		baseView,
2175 							  const float*							texCoord,
2176 							  const ReferenceParams&				sampleParams,
2177 							  const tcu::LookupPrecision&			lookupPrec,
2178 							  const tcu::IVec4&						coordBits,
2179 							  const tcu::LodPrecision&				lodPrec,
2180 							  qpWatchDog*							watchDog)
2181 {
2182 	DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2183 	DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2184 
2185 	std::vector<tcu::ConstPixelBufferAccess>	srcLevelStorage;
2186 	const tcu::TextureCubeArrayView				src					= getEffectiveTextureView(getSubView(baseView, sampleParams.baseLevel, sampleParams.maxLevel), srcLevelStorage, sampleParams.sampler);
2187 
2188 	const tcu::Vec4								sq					= tcu::Vec4(texCoord[0+0], texCoord[4+0], texCoord[8+0], texCoord[12+0]);
2189 	const tcu::Vec4								tq					= tcu::Vec4(texCoord[0+1], texCoord[4+1], texCoord[8+1], texCoord[12+1]);
2190 	const tcu::Vec4								rq					= tcu::Vec4(texCoord[0+2], texCoord[4+2], texCoord[8+2], texCoord[12+2]);
2191 	const tcu::Vec4								qq					= tcu::Vec4(texCoord[0+3], texCoord[4+3], texCoord[8+3], texCoord[12+3]);
2192 
2193 	const tcu::IVec2							dstSize				= tcu::IVec2(result.getWidth(), result.getHeight());
2194 	const float									dstW				= float(dstSize.x());
2195 	const float									dstH				= float(dstSize.y());
2196 	const int									srcSize				= src.getSize();
2197 
2198 	// Coordinates per triangle.
2199 	const tcu::Vec3								triS[2]				= { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2200 	const tcu::Vec3								triT[2]				= { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2201 	const tcu::Vec3								triR[2]				= { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2202 	const tcu::Vec3								triQ[2]				= { qq.swizzle(0, 1, 2), qq.swizzle(3, 2, 1) };
2203 	const tcu::Vec3								triW[2]				= { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2204 
2205 	const tcu::Vec2								lodBias				((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2206 
2207 	const float									posEps				= 1.0f / float((1<<4) + 1); // ES3 requires at least 4 subpixel bits.
2208 
2209 	int											numFailed			= 0;
2210 
2211 	const tcu::Vec2 lodOffsets[] =
2212 	{
2213 		tcu::Vec2(-1,  0),
2214 		tcu::Vec2(+1,  0),
2215 		tcu::Vec2( 0, -1),
2216 		tcu::Vec2( 0, +1),
2217 
2218 		// \note Not strictly allowed by spec, but implementations do this in practice.
2219 		tcu::Vec2(-1, -1),
2220 		tcu::Vec2(-1, +1),
2221 		tcu::Vec2(+1, -1),
2222 		tcu::Vec2(+1, +1),
2223 	};
2224 
2225 	tcu::clear(errorMask, tcu::RGBA::green().toVec());
2226 
2227 	for (int py = 0; py < result.getHeight(); py++)
2228 	{
2229 		// Ugly hack, validation can take way too long at the moment.
2230 		if (watchDog)
2231 			qpWatchDog_touch(watchDog);
2232 
2233 		for (int px = 0; px < result.getWidth(); px++)
2234 		{
2235 			const tcu::Vec4	resPix	= (result.getPixel(px, py)		- sampleParams.colorBias) / sampleParams.colorScale;
2236 			const tcu::Vec4	refPix	= (reference.getPixel(px, py)	- sampleParams.colorBias) / sampleParams.colorScale;
2237 
2238 			// Try comparison to ideal reference first, and if that fails use slower verificator.
2239 			if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(resPix - refPix), lookupPrec.colorThreshold)))
2240 			{
2241 				const float		wx		= (float)px + 0.5f;
2242 				const float		wy		= (float)py + 0.5f;
2243 				const float		nx		= wx / dstW;
2244 				const float		ny		= wy / dstH;
2245 
2246 				const bool		tri0	= nx + ny - posEps <= 1.0f;
2247 				const bool		tri1	= nx + ny + posEps >= 1.0f;
2248 
2249 				bool			isOk	= false;
2250 
2251 				DE_ASSERT(tri0 || tri1);
2252 
2253 				// Pixel can belong to either of the triangles if it lies close enough to the edge.
2254 				for (int triNdx = (tri0?0:1); triNdx <= (tri1?1:0); triNdx++)
2255 				{
2256 					const float		triWx		= triNdx ? dstW - wx : wx;
2257 					const float		triWy		= triNdx ? dstH - wy : wy;
2258 					const float		triNx		= triNdx ? 1.0f - nx : nx;
2259 					const float		triNy		= triNdx ? 1.0f - ny : ny;
2260 
2261 					const tcu::Vec4	coord		(projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2262 												 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2263 												 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy),
2264 												 projectedTriInterpolate(triQ[triNdx], triW[triNdx], triNx, triNy));
2265 					const tcu::Vec3	coordDx		(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2266 												 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
2267 												 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
2268 					const tcu::Vec3	coordDy		(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2269 												 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
2270 												 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
2271 
2272 					tcu::Vec2		lodBounds	= tcu::computeCubeLodBoundsFromDerivates(coord.toWidth<3>(), coordDx, coordDy, srcSize, lodPrec);
2273 
2274 					// Compute lod bounds across lodOffsets range.
2275 					for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2276 					{
2277 						const float		wxo			= triWx + lodOffsets[lodOffsNdx].x();
2278 						const float		wyo			= triWy + lodOffsets[lodOffsNdx].y();
2279 						const float		nxo			= wxo/dstW;
2280 						const float		nyo			= wyo/dstH;
2281 
2282 						const tcu::Vec3	coordO		(projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
2283 													 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
2284 													 projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
2285 						const tcu::Vec3	coordDxo	(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2286 													 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
2287 													 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
2288 						const tcu::Vec3	coordDyo	(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2289 													 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
2290 													 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
2291 						const tcu::Vec2	lodO		= tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
2292 
2293 						lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2294 						lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2295 					}
2296 
2297 					const tcu::Vec2	clampedLod	= tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2298 
2299 					if (tcu::isLookupResultValid(src, sampleParams.sampler, lookupPrec, coordBits, coord, clampedLod, resPix))
2300 					{
2301 						isOk = true;
2302 						break;
2303 					}
2304 				}
2305 
2306 				if (!isOk)
2307 				{
2308 					errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2309 					numFailed += 1;
2310 				}
2311 			}
2312 		}
2313 	}
2314 
2315 	return numFailed;
2316 }
2317 
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)2318 bool verifyTextureResult (tcu::TestContext&						testCtx,
2319 						  const tcu::ConstPixelBufferAccess&	result,
2320 						  const tcu::TextureCubeArrayView&		src,
2321 						  const float*							texCoord,
2322 						  const ReferenceParams&				sampleParams,
2323 						  const tcu::LookupPrecision&			lookupPrec,
2324 						  const tcu::IVec4&						coordBits,
2325 						  const tcu::LodPrecision&				lodPrec,
2326 						  const tcu::PixelFormat&				pixelFormat)
2327 {
2328 	tcu::TestLog&	log				= testCtx.getLog();
2329 	tcu::Surface	reference		(result.getWidth(), result.getHeight());
2330 	tcu::Surface	errorMask		(result.getWidth(), result.getHeight());
2331 	int				numFailedPixels;
2332 
2333 	DE_ASSERT(getCompareMask(pixelFormat) == lookupPrec.colorMask);
2334 
2335 	sampleTexture(tcu::SurfaceAccess(reference, pixelFormat), src, texCoord, sampleParams);
2336 	numFailedPixels = computeTextureLookupDiff(result, reference.getAccess(), errorMask.getAccess(), src, texCoord, sampleParams, lookupPrec, coordBits, lodPrec, testCtx.getWatchDog());
2337 
2338 	if (numFailedPixels > 0)
2339 		log << tcu::TestLog::Message << "ERROR: Result verification failed, got " << numFailedPixels << " invalid pixels!" << tcu::TestLog::EndMessage;
2340 
2341 	log << tcu::TestLog::ImageSet("VerifyResult", "Verification result")
2342 		<< tcu::TestLog::Image("Rendered", "Rendered image", result);
2343 
2344 	if (numFailedPixels > 0)
2345 	{
2346 		log << tcu::TestLog::Image("Reference", "Ideal reference image", reference)
2347 			<< tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
2348 	}
2349 
2350 	log << tcu::TestLog::EndImageSet;
2351 
2352 	return numFailedPixels == 0;
2353 }
2354 
2355 // Shadow lookup verification
2356 
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)2357 int computeTextureCompareDiff (const tcu::ConstPixelBufferAccess&	result,
2358 							   const tcu::ConstPixelBufferAccess&	reference,
2359 							   const tcu::PixelBufferAccess&		errorMask,
2360 							   const tcu::Texture2DView&			src,
2361 							   const float*							texCoord,
2362 							   const ReferenceParams&				sampleParams,
2363 							   const tcu::TexComparePrecision&		comparePrec,
2364 							   const tcu::LodPrecision&				lodPrec,
2365 							   const tcu::Vec3&						nonShadowThreshold)
2366 {
2367 	DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2368 	DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2369 
2370 	const tcu::Vec4		sq				= tcu::Vec4(texCoord[0+0], texCoord[2+0], texCoord[4+0], texCoord[6+0]);
2371 	const tcu::Vec4		tq				= tcu::Vec4(texCoord[0+1], texCoord[2+1], texCoord[4+1], texCoord[6+1]);
2372 
2373 	const tcu::IVec2	dstSize			= tcu::IVec2(result.getWidth(), result.getHeight());
2374 	const float			dstW			= float(dstSize.x());
2375 	const float			dstH			= float(dstSize.y());
2376 	const tcu::IVec2	srcSize			= tcu::IVec2(src.getWidth(), src.getHeight());
2377 
2378 	// Coordinates and lod per triangle.
2379 	const tcu::Vec3		triS[2]			= { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2380 	const tcu::Vec3		triT[2]			= { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2381 	const tcu::Vec3		triW[2]			= { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2382 
2383 	const tcu::Vec2		lodBias			((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2384 
2385 	int					numFailed		= 0;
2386 
2387 	const tcu::Vec2 lodOffsets[] =
2388 	{
2389 		tcu::Vec2(-1,  0),
2390 		tcu::Vec2(+1,  0),
2391 		tcu::Vec2( 0, -1),
2392 		tcu::Vec2( 0, +1),
2393 	};
2394 
2395 	tcu::clear(errorMask, tcu::RGBA::green().toVec());
2396 
2397 	for (int py = 0; py < result.getHeight(); py++)
2398 	{
2399 		for (int px = 0; px < result.getWidth(); px++)
2400 		{
2401 			const tcu::Vec4	resPix	= result.getPixel(px, py);
2402 			const tcu::Vec4	refPix	= reference.getPixel(px, py);
2403 
2404 			// Other channels should trivially match to reference.
2405 			if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold)))
2406 			{
2407 				errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2408 				numFailed += 1;
2409 				continue;
2410 			}
2411 
2412 			// Reference result is known to be a valid result, we can
2413 			// skip verification if thes results are equal
2414 			if (resPix.x() != refPix.x())
2415 			{
2416 				const float		wx		= (float)px + 0.5f;
2417 				const float		wy		= (float)py + 0.5f;
2418 				const float		nx		= wx / dstW;
2419 				const float		ny		= wy / dstH;
2420 
2421 				const int		triNdx	= nx + ny >= 1.0f ? 1 : 0;
2422 				const float		triWx	= triNdx ? dstW - wx : wx;
2423 				const float		triWy	= triNdx ? dstH - wy : wy;
2424 				const float		triNx	= triNdx ? 1.0f - nx : nx;
2425 				const float		triNy	= triNdx ? 1.0f - ny : ny;
2426 
2427 				const tcu::Vec2	coord		(projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2428 											 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy));
2429 				const tcu::Vec2	coordDx		= tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2430 														triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
2431 				const tcu::Vec2	coordDy		= tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2432 														triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
2433 
2434 				tcu::Vec2		lodBounds	= tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
2435 
2436 				// Compute lod bounds across lodOffsets range.
2437 				for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2438 				{
2439 					const float		wxo		= triWx + lodOffsets[lodOffsNdx].x();
2440 					const float		wyo		= triWy + lodOffsets[lodOffsNdx].y();
2441 					const float		nxo		= wxo/dstW;
2442 					const float		nyo		= wyo/dstH;
2443 
2444 					const tcu::Vec2	coordDxo	= tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2445 															triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
2446 					const tcu::Vec2	coordDyo	= tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2447 															triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
2448 					const tcu::Vec2	lodO		= tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
2449 
2450 					lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2451 					lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2452 				}
2453 
2454 				const tcu::Vec2	clampedLod	= tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2455 				const bool		isOk		= tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x());
2456 
2457 				if (!isOk)
2458 				{
2459 					errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2460 					numFailed += 1;
2461 				}
2462 			}
2463 		}
2464 	}
2465 
2466 	return numFailed;
2467 }
2468 
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)2469 int computeTextureCompareDiff (const tcu::ConstPixelBufferAccess&	result,
2470 							   const tcu::ConstPixelBufferAccess&	reference,
2471 							   const tcu::PixelBufferAccess&		errorMask,
2472 							   const tcu::TextureCubeView&			src,
2473 							   const float*							texCoord,
2474 							   const ReferenceParams&				sampleParams,
2475 							   const tcu::TexComparePrecision&		comparePrec,
2476 							   const tcu::LodPrecision&				lodPrec,
2477 							   const tcu::Vec3&						nonShadowThreshold)
2478 {
2479 	DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2480 	DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2481 
2482 	const tcu::Vec4		sq				= tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
2483 	const tcu::Vec4		tq				= tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
2484 	const tcu::Vec4		rq				= tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
2485 
2486 	const tcu::IVec2	dstSize			= tcu::IVec2(result.getWidth(), result.getHeight());
2487 	const float			dstW			= float(dstSize.x());
2488 	const float			dstH			= float(dstSize.y());
2489 	const int			srcSize			= src.getSize();
2490 
2491 	// Coordinates per triangle.
2492 	const tcu::Vec3		triS[2]			= { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2493 	const tcu::Vec3		triT[2]			= { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2494 	const tcu::Vec3		triR[2]			= { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2495 	const tcu::Vec3		triW[2]			= { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2496 
2497 	const tcu::Vec2		lodBias			((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2498 
2499 	int					numFailed		= 0;
2500 
2501 	const tcu::Vec2 lodOffsets[] =
2502 	{
2503 		tcu::Vec2(-1,  0),
2504 		tcu::Vec2(+1,  0),
2505 		tcu::Vec2( 0, -1),
2506 		tcu::Vec2( 0, +1),
2507 	};
2508 
2509 	tcu::clear(errorMask, tcu::RGBA::green().toVec());
2510 
2511 	for (int py = 0; py < result.getHeight(); py++)
2512 	{
2513 		for (int px = 0; px < result.getWidth(); px++)
2514 		{
2515 			const tcu::Vec4	resPix	= result.getPixel(px, py);
2516 			const tcu::Vec4	refPix	= reference.getPixel(px, py);
2517 
2518 			// Other channels should trivially match to reference.
2519 			if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold)))
2520 			{
2521 				errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2522 				numFailed += 1;
2523 				continue;
2524 			}
2525 
2526 			// Reference result is known to be a valid result, we can
2527 			// skip verification if thes results are equal
2528 			if (resPix.x() != refPix.x())
2529 			{
2530 				const float		wx		= (float)px + 0.5f;
2531 				const float		wy		= (float)py + 0.5f;
2532 				const float		nx		= wx / dstW;
2533 				const float		ny		= wy / dstH;
2534 
2535 				const int		triNdx	= nx + ny >= 1.0f ? 1 : 0;
2536 				const float		triWx	= triNdx ? dstW - wx : wx;
2537 				const float		triWy	= triNdx ? dstH - wy : wy;
2538 				const float		triNx	= triNdx ? 1.0f - nx : nx;
2539 				const float		triNy	= triNdx ? 1.0f - ny : ny;
2540 
2541 				const tcu::Vec3	coord		(projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2542 											 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2543 											 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2544 				const tcu::Vec3	coordDx		(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2545 											 triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy),
2546 											 triDerivateX(triR[triNdx], triW[triNdx], wx, dstW, triNy));
2547 				const tcu::Vec3	coordDy		(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2548 											 triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx),
2549 											 triDerivateY(triR[triNdx], triW[triNdx], wy, dstH, triNx));
2550 
2551 				tcu::Vec2		lodBounds	= tcu::computeCubeLodBoundsFromDerivates(coord, coordDx, coordDy, srcSize, lodPrec);
2552 
2553 				// Compute lod bounds across lodOffsets range.
2554 				for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2555 				{
2556 					const float		wxo		= triWx + lodOffsets[lodOffsNdx].x();
2557 					const float		wyo		= triWy + lodOffsets[lodOffsNdx].y();
2558 					const float		nxo		= wxo/dstW;
2559 					const float		nyo		= wyo/dstH;
2560 
2561 					const tcu::Vec3	coordO		(projectedTriInterpolate(triS[triNdx], triW[triNdx], nxo, nyo),
2562 												 projectedTriInterpolate(triT[triNdx], triW[triNdx], nxo, nyo),
2563 												 projectedTriInterpolate(triR[triNdx], triW[triNdx], nxo, nyo));
2564 					const tcu::Vec3	coordDxo	(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2565 												 triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo),
2566 												 triDerivateX(triR[triNdx], triW[triNdx], wxo, dstW, nyo));
2567 					const tcu::Vec3	coordDyo	(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2568 												 triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo),
2569 												 triDerivateY(triR[triNdx], triW[triNdx], wyo, dstH, nxo));
2570 					const tcu::Vec2	lodO		= tcu::computeCubeLodBoundsFromDerivates(coordO, coordDxo, coordDyo, srcSize, lodPrec);
2571 
2572 					lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2573 					lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2574 				}
2575 
2576 				const tcu::Vec2	clampedLod	= tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2577 				const bool		isOk		= tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x());
2578 
2579 				if (!isOk)
2580 				{
2581 					errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2582 					numFailed += 1;
2583 				}
2584 			}
2585 		}
2586 	}
2587 
2588 	return numFailed;
2589 }
2590 
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)2591 int computeTextureCompareDiff (const tcu::ConstPixelBufferAccess&	result,
2592 							   const tcu::ConstPixelBufferAccess&	reference,
2593 							   const tcu::PixelBufferAccess&		errorMask,
2594 							   const tcu::Texture2DArrayView&		src,
2595 							   const float*							texCoord,
2596 							   const ReferenceParams&				sampleParams,
2597 							   const tcu::TexComparePrecision&		comparePrec,
2598 							   const tcu::LodPrecision&				lodPrec,
2599 							   const tcu::Vec3&						nonShadowThreshold)
2600 {
2601 	DE_ASSERT(result.getWidth() == reference.getWidth() && result.getHeight() == reference.getHeight());
2602 	DE_ASSERT(result.getWidth() == errorMask.getWidth() && result.getHeight() == errorMask.getHeight());
2603 
2604 	const tcu::Vec4		sq				= tcu::Vec4(texCoord[0+0], texCoord[3+0], texCoord[6+0], texCoord[9+0]);
2605 	const tcu::Vec4		tq				= tcu::Vec4(texCoord[0+1], texCoord[3+1], texCoord[6+1], texCoord[9+1]);
2606 	const tcu::Vec4		rq				= tcu::Vec4(texCoord[0+2], texCoord[3+2], texCoord[6+2], texCoord[9+2]);
2607 
2608 	const tcu::IVec2	dstSize			= tcu::IVec2(result.getWidth(), result.getHeight());
2609 	const float			dstW			= float(dstSize.x());
2610 	const float			dstH			= float(dstSize.y());
2611 	const tcu::IVec2	srcSize			= tcu::IVec2(src.getWidth(), src.getHeight());
2612 
2613 	// Coordinates and lod per triangle.
2614 	const tcu::Vec3		triS[2]			= { sq.swizzle(0, 1, 2), sq.swizzle(3, 2, 1) };
2615 	const tcu::Vec3		triT[2]			= { tq.swizzle(0, 1, 2), tq.swizzle(3, 2, 1) };
2616 	const tcu::Vec3		triR[2]			= { rq.swizzle(0, 1, 2), rq.swizzle(3, 2, 1) };
2617 	const tcu::Vec3		triW[2]			= { sampleParams.w.swizzle(0, 1, 2), sampleParams.w.swizzle(3, 2, 1) };
2618 
2619 	const tcu::Vec2		lodBias			((sampleParams.flags & ReferenceParams::USE_BIAS) ? sampleParams.bias : 0.0f);
2620 
2621 	int					numFailed		= 0;
2622 
2623 	const tcu::Vec2 lodOffsets[] =
2624 	{
2625 		tcu::Vec2(-1,  0),
2626 		tcu::Vec2(+1,  0),
2627 		tcu::Vec2( 0, -1),
2628 		tcu::Vec2( 0, +1),
2629 	};
2630 
2631 	tcu::clear(errorMask, tcu::RGBA::green().toVec());
2632 
2633 	for (int py = 0; py < result.getHeight(); py++)
2634 	{
2635 		for (int px = 0; px < result.getWidth(); px++)
2636 		{
2637 			const tcu::Vec4	resPix	= result.getPixel(px, py);
2638 			const tcu::Vec4	refPix	= reference.getPixel(px, py);
2639 
2640 			// Other channels should trivially match to reference.
2641 			if (!tcu::boolAll(tcu::lessThanEqual(tcu::abs(refPix.swizzle(1,2,3) - resPix.swizzle(1,2,3)), nonShadowThreshold)))
2642 			{
2643 				errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2644 				numFailed += 1;
2645 				continue;
2646 			}
2647 
2648 			// Reference result is known to be a valid result, we can
2649 			// skip verification if thes results are equal
2650 			if (resPix.x() != refPix.x())
2651 			{
2652 				const float		wx		= (float)px + 0.5f;
2653 				const float		wy		= (float)py + 0.5f;
2654 				const float		nx		= wx / dstW;
2655 				const float		ny		= wy / dstH;
2656 
2657 				const int		triNdx	= nx + ny >= 1.0f ? 1 : 0;
2658 				const float		triWx	= triNdx ? dstW - wx : wx;
2659 				const float		triWy	= triNdx ? dstH - wy : wy;
2660 				const float		triNx	= triNdx ? 1.0f - nx : nx;
2661 				const float		triNy	= triNdx ? 1.0f - ny : ny;
2662 
2663 				const tcu::Vec3	coord		(projectedTriInterpolate(triS[triNdx], triW[triNdx], triNx, triNy),
2664 											 projectedTriInterpolate(triT[triNdx], triW[triNdx], triNx, triNy),
2665 											 projectedTriInterpolate(triR[triNdx], triW[triNdx], triNx, triNy));
2666 				const tcu::Vec2	coordDx		= tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wx, dstW, triNy),
2667 														triDerivateX(triT[triNdx], triW[triNdx], wx, dstW, triNy)) * srcSize.asFloat();
2668 				const tcu::Vec2	coordDy		= tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wy, dstH, triNx),
2669 														triDerivateY(triT[triNdx], triW[triNdx], wy, dstH, triNx)) * srcSize.asFloat();
2670 
2671 				tcu::Vec2		lodBounds	= tcu::computeLodBoundsFromDerivates(coordDx.x(), coordDx.y(), coordDy.x(), coordDy.y(), lodPrec);
2672 
2673 				// Compute lod bounds across lodOffsets range.
2674 				for (int lodOffsNdx = 0; lodOffsNdx < DE_LENGTH_OF_ARRAY(lodOffsets); lodOffsNdx++)
2675 				{
2676 					const float		wxo		= triWx + lodOffsets[lodOffsNdx].x();
2677 					const float		wyo		= triWy + lodOffsets[lodOffsNdx].y();
2678 					const float		nxo		= wxo/dstW;
2679 					const float		nyo		= wyo/dstH;
2680 
2681 					const tcu::Vec2	coordDxo	= tcu::Vec2(triDerivateX(triS[triNdx], triW[triNdx], wxo, dstW, nyo),
2682 															triDerivateX(triT[triNdx], triW[triNdx], wxo, dstW, nyo)) * srcSize.asFloat();
2683 					const tcu::Vec2	coordDyo	= tcu::Vec2(triDerivateY(triS[triNdx], triW[triNdx], wyo, dstH, nxo),
2684 															triDerivateY(triT[triNdx], triW[triNdx], wyo, dstH, nxo)) * srcSize.asFloat();
2685 					const tcu::Vec2	lodO		= tcu::computeLodBoundsFromDerivates(coordDxo.x(), coordDxo.y(), coordDyo.x(), coordDyo.y(), lodPrec);
2686 
2687 					lodBounds.x() = de::min(lodBounds.x(), lodO.x());
2688 					lodBounds.y() = de::max(lodBounds.y(), lodO.y());
2689 				}
2690 
2691 				const tcu::Vec2	clampedLod	= tcu::clampLodBounds(lodBounds + lodBias, tcu::Vec2(sampleParams.minLod, sampleParams.maxLod), lodPrec);
2692 				const bool		isOk		= tcu::isTexCompareResultValid(src, sampleParams.sampler, comparePrec, coord, clampedLod, sampleParams.ref, resPix.x());
2693 
2694 				if (!isOk)
2695 				{
2696 					errorMask.setPixel(tcu::RGBA::red().toVec(), px, py);
2697 					numFailed += 1;
2698 				}
2699 			}
2700 		}
2701 	}
2702 
2703 	return numFailed;
2704 }
2705 
2706 // Mipmap generation comparison.
2707 
compareGenMipmapBilinear(const tcu::ConstPixelBufferAccess & dst,const tcu::ConstPixelBufferAccess & src,const tcu::PixelBufferAccess & errorMask,const GenMipmapPrecision & precision)2708 static int compareGenMipmapBilinear (const tcu::ConstPixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& errorMask, const GenMipmapPrecision& precision)
2709 {
2710 	DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures.
2711 
2712 	const float		dstW		= float(dst.getWidth());
2713 	const float		dstH		= float(dst.getHeight());
2714 	const float		srcW		= float(src.getWidth());
2715 	const float		srcH		= float(src.getHeight());
2716 	int				numFailed	= 0;
2717 
2718 	// Translation to lookup verification parameters.
2719 	const tcu::Sampler		sampler		(tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
2720 										 tcu::Sampler::LINEAR, tcu::Sampler::LINEAR, 0.0f, false /* non-normalized coords */);
2721 	tcu::LookupPrecision	lookupPrec;
2722 
2723 	lookupPrec.colorThreshold	= precision.colorThreshold;
2724 	lookupPrec.colorMask		= precision.colorMask;
2725 	lookupPrec.coordBits		= tcu::IVec3(22);
2726 	lookupPrec.uvwBits			= precision.filterBits;
2727 
2728 	for (int y = 0; y < dst.getHeight(); y++)
2729 	for (int x = 0; x < dst.getWidth(); x++)
2730 	{
2731 		const tcu::Vec4	result	= dst.getPixel(x, y);
2732 		const float		cx		= (float(x)+0.5f) / dstW * srcW;
2733 		const float		cy		= (float(y)+0.5f) / dstH * srcH;
2734 		const bool		isOk	= tcu::isLinearSampleResultValid(src, sampler, lookupPrec, tcu::Vec2(cx, cy), 0, result);
2735 
2736 		errorMask.setPixel(isOk ? tcu::RGBA::green().toVec() : tcu::RGBA::red().toVec(), x, y);
2737 		if (!isOk)
2738 			numFailed += 1;
2739 	}
2740 
2741 	return numFailed;
2742 }
2743 
compareGenMipmapBox(const tcu::ConstPixelBufferAccess & dst,const tcu::ConstPixelBufferAccess & src,const tcu::PixelBufferAccess & errorMask,const GenMipmapPrecision & precision)2744 static int compareGenMipmapBox (const tcu::ConstPixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& errorMask, const GenMipmapPrecision& precision)
2745 {
2746 	DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures.
2747 
2748 	const float		dstW		= float(dst.getWidth());
2749 	const float		dstH		= float(dst.getHeight());
2750 	const float		srcW		= float(src.getWidth());
2751 	const float		srcH		= float(src.getHeight());
2752 	int				numFailed	= 0;
2753 
2754 	// Translation to lookup verification parameters.
2755 	const tcu::Sampler		sampler		(tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE, tcu::Sampler::CLAMP_TO_EDGE,
2756 										 tcu::Sampler::LINEAR, tcu::Sampler::LINEAR, 0.0f, false /* non-normalized coords */);
2757 	tcu::LookupPrecision	lookupPrec;
2758 
2759 	lookupPrec.colorThreshold	= precision.colorThreshold;
2760 	lookupPrec.colorMask		= precision.colorMask;
2761 	lookupPrec.coordBits		= tcu::IVec3(22);
2762 	lookupPrec.uvwBits			= precision.filterBits;
2763 
2764 	for (int y = 0; y < dst.getHeight(); y++)
2765 	for (int x = 0; x < dst.getWidth(); x++)
2766 	{
2767 		const tcu::Vec4	result	= dst.getPixel(x, y);
2768 		const float		cx		= deFloatFloor(float(x) / dstW * srcW) + 1.0f;
2769 		const float		cy		= deFloatFloor(float(y) / dstH * srcH) + 1.0f;
2770 		const bool		isOk	= tcu::isLinearSampleResultValid(src, sampler, lookupPrec, tcu::Vec2(cx, cy), 0, result);
2771 
2772 		errorMask.setPixel(isOk ? tcu::RGBA::green().toVec() : tcu::RGBA::red().toVec(), x, y);
2773 		if (!isOk)
2774 			numFailed += 1;
2775 	}
2776 
2777 	return numFailed;
2778 }
2779 
compareGenMipmapVeryLenient(const tcu::ConstPixelBufferAccess & dst,const tcu::ConstPixelBufferAccess & src,const tcu::PixelBufferAccess & errorMask,const GenMipmapPrecision & precision)2780 static int compareGenMipmapVeryLenient (const tcu::ConstPixelBufferAccess& dst, const tcu::ConstPixelBufferAccess& src, const tcu::PixelBufferAccess& errorMask, const GenMipmapPrecision& precision)
2781 {
2782 	DE_ASSERT(dst.getDepth() == 1 && src.getDepth() == 1); // \todo [2013-10-29 pyry] 3D textures.
2783 	DE_UNREF(precision);
2784 
2785 	const float		dstW		= float(dst.getWidth());
2786 	const float		dstH		= float(dst.getHeight());
2787 	const float		srcW		= float(src.getWidth());
2788 	const float		srcH		= float(src.getHeight());
2789 	int				numFailed	= 0;
2790 
2791 	for (int y = 0; y < dst.getHeight(); y++)
2792 	for (int x = 0; x < dst.getWidth(); x++)
2793 	{
2794 		const tcu::Vec4	result	= dst.getPixel(x, y);
2795 		const int		minX		= deFloorFloatToInt32(((float)x-0.5f) / dstW * srcW);
2796 		const int		minY		= deFloorFloatToInt32(((float)y-0.5f) / dstH * srcH);
2797 		const int		maxX		= deCeilFloatToInt32(((float)x+1.5f) / dstW * srcW);
2798 		const int		maxY		= deCeilFloatToInt32(((float)y+1.5f) / dstH * srcH);
2799 		tcu::Vec4		minVal, maxVal;
2800 		bool			isOk;
2801 
2802 		DE_ASSERT(minX < maxX && minY < maxY);
2803 
2804 		for (int ky = minY; ky <= maxY; ky++)
2805 		{
2806 			for (int kx = minX; kx <= maxX; kx++)
2807 			{
2808 				const int		sx		= de::clamp(kx, 0, src.getWidth()-1);
2809 				const int		sy		= de::clamp(ky, 0, src.getHeight()-1);
2810 				const tcu::Vec4	sample	= src.getPixel(sx, sy);
2811 
2812 				if (ky == minY && kx == minX)
2813 				{
2814 					minVal = sample;
2815 					maxVal = sample;
2816 				}
2817 				else
2818 				{
2819 					minVal = min(sample, minVal);
2820 					maxVal = max(sample, maxVal);
2821 				}
2822 			}
2823 		}
2824 
2825 		isOk = boolAll(logicalAnd(lessThanEqual(minVal, result), lessThanEqual(result, maxVal)));
2826 
2827 		errorMask.setPixel(isOk ? tcu::RGBA::green().toVec() : tcu::RGBA::red().toVec(), x, y);
2828 		if (!isOk)
2829 			numFailed += 1;
2830 	}
2831 
2832 	return numFailed;
2833 }
2834 
compareGenMipmapResult(tcu::TestLog & log,const tcu::Texture2D & resultTexture,const tcu::Texture2D & level0Reference,const GenMipmapPrecision & precision)2835 qpTestResult compareGenMipmapResult (tcu::TestLog& log, const tcu::Texture2D& resultTexture, const tcu::Texture2D& level0Reference, const GenMipmapPrecision& precision)
2836 {
2837 	qpTestResult result = QP_TEST_RESULT_PASS;
2838 
2839 	// Special comparison for level 0.
2840 	{
2841 		const tcu::Vec4		threshold	= select(precision.colorThreshold, tcu::Vec4(1.0f), precision.colorMask);
2842 		const bool			level0Ok	= tcu::floatThresholdCompare(log, "Level0", "Level 0", level0Reference.getLevel(0), resultTexture.getLevel(0), threshold, tcu::COMPARE_LOG_RESULT);
2843 
2844 		if (!level0Ok)
2845 		{
2846 			log << tcu::TestLog::Message << "ERROR: Level 0 comparison failed!" << tcu::TestLog::EndMessage;
2847 			result = QP_TEST_RESULT_FAIL;
2848 		}
2849 	}
2850 
2851 	for (int levelNdx = 1; levelNdx < resultTexture.getNumLevels(); levelNdx++)
2852 	{
2853 		const tcu::ConstPixelBufferAccess	src			= resultTexture.getLevel(levelNdx-1);
2854 		const tcu::ConstPixelBufferAccess	dst			= resultTexture.getLevel(levelNdx);
2855 		tcu::Surface						errorMask	(dst.getWidth(), dst.getHeight());
2856 		bool								levelOk		= false;
2857 
2858 		// Try different comparisons in quality order.
2859 
2860 		if (!levelOk)
2861 		{
2862 			const int numFailed = compareGenMipmapBilinear(dst, src, errorMask.getAccess(), precision);
2863 			if (numFailed == 0)
2864 				levelOk = true;
2865 			else
2866 				log << tcu::TestLog::Message << "WARNING: Level " << levelNdx << " comparison to bilinear method failed, found " << numFailed << " invalid pixels." << tcu::TestLog::EndMessage;
2867 		}
2868 
2869 		if (!levelOk)
2870 		{
2871 			const int numFailed = compareGenMipmapBox(dst, src, errorMask.getAccess(), precision);
2872 			if (numFailed == 0)
2873 				levelOk = true;
2874 			else
2875 				log << tcu::TestLog::Message << "WARNING: Level " << levelNdx << " comparison to box method failed, found " << numFailed << " invalid pixels." << tcu::TestLog::EndMessage;
2876 		}
2877 
2878 		// At this point all high-quality methods have been used.
2879 		if (!levelOk && result == QP_TEST_RESULT_PASS)
2880 			result = QP_TEST_RESULT_QUALITY_WARNING;
2881 
2882 		if (!levelOk)
2883 		{
2884 			const int numFailed = compareGenMipmapVeryLenient(dst, src, errorMask.getAccess(), precision);
2885 			if (numFailed == 0)
2886 				levelOk = true;
2887 			else
2888 				log << tcu::TestLog::Message << "ERROR: Level " << levelNdx << " appears to contain " << numFailed << " completely wrong pixels, failing case!" << tcu::TestLog::EndMessage;
2889 		}
2890 
2891 		if (!levelOk)
2892 			result = QP_TEST_RESULT_FAIL;
2893 
2894 		log << tcu::TestLog::ImageSet(string("Level") + de::toString(levelNdx), string("Level ") + de::toString(levelNdx) + " result")
2895 			<< tcu::TestLog::Image("Result", "Result", dst);
2896 
2897 		if (!levelOk)
2898 			log << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
2899 
2900 		log << tcu::TestLog::EndImageSet;
2901 	}
2902 
2903 	return result;
2904 }
2905 
compareGenMipmapResult(tcu::TestLog & log,const tcu::TextureCube & resultTexture,const tcu::TextureCube & level0Reference,const GenMipmapPrecision & precision)2906 qpTestResult compareGenMipmapResult (tcu::TestLog& log, const tcu::TextureCube& resultTexture, const tcu::TextureCube& level0Reference, const GenMipmapPrecision& precision)
2907 {
2908 	qpTestResult result = QP_TEST_RESULT_PASS;
2909 
2910 	static const char* s_faceNames[] = { "-X", "+X", "-Y", "+Y", "-Z", "+Z" };
2911 	DE_STATIC_ASSERT(DE_LENGTH_OF_ARRAY(s_faceNames) == tcu::CUBEFACE_LAST);
2912 
2913 	// Special comparison for level 0.
2914 	for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
2915 	{
2916 		const tcu::CubeFace	face		= tcu::CubeFace(faceNdx);
2917 		const tcu::Vec4		threshold	= select(precision.colorThreshold, tcu::Vec4(1.0f), precision.colorMask);
2918 		const bool			level0Ok	= tcu::floatThresholdCompare(log,
2919 																	 ("Level0Face" + de::toString(faceNdx)).c_str(),
2920 																	 (string("Level 0, face ") + s_faceNames[face]).c_str(),
2921 																	 level0Reference.getLevelFace(0, face),
2922 																	 resultTexture.getLevelFace(0, face),
2923 																	 threshold, tcu::COMPARE_LOG_RESULT);
2924 
2925 		if (!level0Ok)
2926 		{
2927 			log << tcu::TestLog::Message << "ERROR: Level 0, face " << s_faceNames[face] << " comparison failed!" << tcu::TestLog::EndMessage;
2928 			result = QP_TEST_RESULT_FAIL;
2929 		}
2930 	}
2931 
2932 	for (int levelNdx = 1; levelNdx < resultTexture.getNumLevels(); levelNdx++)
2933 	{
2934 		for (int faceNdx = 0; faceNdx < tcu::CUBEFACE_LAST; faceNdx++)
2935 		{
2936 			const tcu::CubeFace					face		= tcu::CubeFace(faceNdx);
2937 			const char*							faceName	= s_faceNames[face];
2938 			const tcu::ConstPixelBufferAccess	src			= resultTexture.getLevelFace(levelNdx-1,	face);
2939 			const tcu::ConstPixelBufferAccess	dst			= resultTexture.getLevelFace(levelNdx,		face);
2940 			tcu::Surface						errorMask	(dst.getWidth(), dst.getHeight());
2941 			bool								levelOk		= false;
2942 
2943 			// Try different comparisons in quality order.
2944 
2945 			if (!levelOk)
2946 			{
2947 				const int numFailed = compareGenMipmapBilinear(dst, src, errorMask.getAccess(), precision);
2948 				if (numFailed == 0)
2949 					levelOk = true;
2950 				else
2951 					log << tcu::TestLog::Message << "WARNING: Level " << levelNdx << ", face " << faceName << " comparison to bilinear method failed, found " << numFailed << " invalid pixels." << tcu::TestLog::EndMessage;
2952 			}
2953 
2954 			if (!levelOk)
2955 			{
2956 				const int numFailed = compareGenMipmapBox(dst, src, errorMask.getAccess(), precision);
2957 				if (numFailed == 0)
2958 					levelOk = true;
2959 				else
2960 					log << tcu::TestLog::Message << "WARNING: Level " << levelNdx << ", face " << faceName <<" comparison to box method failed, found " << numFailed << " invalid pixels." << tcu::TestLog::EndMessage;
2961 			}
2962 
2963 			// At this point all high-quality methods have been used.
2964 			if (!levelOk && result == QP_TEST_RESULT_PASS)
2965 				result = QP_TEST_RESULT_QUALITY_WARNING;
2966 
2967 			if (!levelOk)
2968 			{
2969 				const int numFailed = compareGenMipmapVeryLenient(dst, src, errorMask.getAccess(), precision);
2970 				if (numFailed == 0)
2971 					levelOk = true;
2972 				else
2973 					log << tcu::TestLog::Message << "ERROR: Level " << levelNdx << ", face " << faceName << " appears to contain " << numFailed << " completely wrong pixels, failing case!" << tcu::TestLog::EndMessage;
2974 			}
2975 
2976 			if (!levelOk)
2977 				result = QP_TEST_RESULT_FAIL;
2978 
2979 			log << tcu::TestLog::ImageSet(string("Level") + de::toString(levelNdx) + "Face" + de::toString(faceNdx), string("Level ") + de::toString(levelNdx) + ", face " + string(faceName) + " result")
2980 				<< tcu::TestLog::Image("Result", "Result", dst);
2981 
2982 			if (!levelOk)
2983 				log << tcu::TestLog::Image("ErrorMask", "Error mask", errorMask);
2984 
2985 			log << tcu::TestLog::EndImageSet;
2986 		}
2987 	}
2988 
2989 	return result;
2990 }
2991 
2992 // Logging utilities.
2993 
operator <<(std::ostream & str,const LogGradientFmt & fmt)2994 std::ostream& operator<< (std::ostream& str, const LogGradientFmt& fmt)
2995 {
2996 	return str << "(R: " << fmt.valueMin->x() << " -> " << fmt.valueMax->x() << ", "
2997 			   <<  "G: " << fmt.valueMin->y() << " -> " << fmt.valueMax->y() << ", "
2998 			   <<  "B: " << fmt.valueMin->z() << " -> " << fmt.valueMax->z() << ", "
2999 			   <<  "A: " << fmt.valueMin->w() << " -> " << fmt.valueMax->w() << ")";
3000 }
3001 
3002 } // TextureTestUtil
3003 } // glu
3004