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