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